#define _GNU_SOURCE
#include "app_serial.h"
#include "log/log.h"
int app_serial_setBaudRate(Device *device, BaudRate rate)
{
    //获取当前串口的配置属性
    struct termios attr;
    tcgetattr(device->fd, &attr);
    //修改属性
    cfsetspeed(&attr, rate);
    //设置串口属性,刷新后生效
    int ret = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (ret != 0)
    {
        log_error("设置串口属性失败");
        return -1;
    }
    log_debug("设置串口波特率成功");
    return 0;
}

int app_serial_setParity(Device *device, Parity parity)
{
    //获取当前串口的配置属性
    struct termios attr;
    tcgetattr(device->fd, &attr);
    //修改属性
    attr.c_cflag &= ~(PARENB | PARODD);
    attr.c_cflag |= parity;
    //设置串口属性,刷新后生效
    int ret = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (ret != 0)
    {
        log_error("设置串口校验位失败");
        return -1;
    }
    log_debug("串口校验位设置成功");
    return 0;
}

int app_serial_setStopBits(Device *device, StopBits stopBits)
{
    //获取当前串口的配置属性
    struct termios attr;
    tcgetattr(device->fd, &attr);
    //修改属性
    attr.c_cflag &= ~CSTOPB;
    attr.c_cflag |= stopBits;
    //设置串口属性,刷新后生效
    int ret = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (ret != 0)
    {
        log_error("设置串口停止位失败");
        return -1;
    }
    log_debug("串口停止位设置成功");
    return 0;
}

int app_serial_setBlock(Device *device, int is_block)
{
    //获取当前串口的配置属性
    struct termios attr;
    tcgetattr(device->fd, &attr);
    //修改属性（1阻塞/ 0非阻塞）
    if (is_block) 
    {
        attr.c_cc[VMIN] = 1; //至少读取一个字符才返回
        attr.c_cc[VTIME] = 0; //如果没有数据，等待多长时间返回 0：一直等  
    }
    else 
    {
        attr.c_cc[VMIN] = 0; // 没有读取一个字符也可返回
        attr.c_cc[VTIME] = 2;   //如果没有数据，等待0.2s时间返回 （单位100毫秒）
    }
    
    //设置串口属性,刷新后生效
    int ret = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (ret != 0)
    {
        log_error("设置串口是否阻塞失败");
        return -1;
    }
    log_debug("串口是否阻塞设置成功");
    return 0;
}

int app_serial_setRaw(Device *device)
{
    //获取当前串口的配置属性
    struct termios attr;
    tcgetattr(device->fd, &attr);
    //修改属性(设置原始模式，不解析特殊字符)
    cfmakeraw(&attr);
    //设置串口属性,刷新后生效
    int ret = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (ret != 0)
    {
        log_error("设置串口原始模式失败");
        return -1;
    }
    log_debug("串口原始模式设置成功");
    return 0;
}

int app_serial_init(Device *device)
{
    //初始化属性设置
    app_serial_setBaudRate(device, BR_9600);        //9600
    app_serial_setParity(device, Parity_NONE);  //无校验     
    app_serial_setStopBits(device, Stop_1); //1位停止位
    //app_serial_setBlock(device, 0); //非阻塞模式
    app_serial_setRaw(device);  //原始模式

    //刷新
    int ret = tcflush(device->fd, TCIOFLUSH);
    if (ret != 0)
    {
        log_error("串口初始化失败");
        return -1;
    }
    log_debug("串口初始化成功");
    return 0;
}

int app_serial_flush(Device *device)
{
    return tcflush(device->fd, TCIOFLUSH);
}
